package com.bz.xtcx.manager.config;

import com.alibaba.fastjson.JSONObject;
import com.bz.xtcx.manager.utils.WzStrUtil;
import com.bz.xtcx.manager.vo.VoResponse;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Map;

/**
 * @author zhangkj
 *
 */
public class XSSAndSqlFilter implements Filter{
    private String badKey = "'|and|exec|execute|insert|select|delete|update|count|drop|%|chr|mid|master|truncate|"
            + "char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|"
            + "table|from|grant|use|group_concat|column_name|"
            + "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|"
            + "chr|mid|master|truncate|char|declare|or|;|-|--|,|like|//|/|%|#|eval|javascript|script|e-xpression";

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(XSSAndSqlFilter.class);
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.debug("过滤XSS危险及SQL注入问题");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        VoResponse voRes = new VoResponse();
        voRes.setFail(voRes);
        voRes.setMessage("参数非法，请检查录入参数重新登录");
        WzHttpServletRequestWrapper req = null;
        if (request instanceof WzHttpServletRequestWrapper) {
            req = (WzHttpServletRequestWrapper) request;
        } else {
            req = new WzHttpServletRequestWrapper((HttpServletRequest) request);
        }
        req.setCharacterEncoding("UTF-8");
        HttpServletResponse res = (HttpServletResponse) response;
        res.setCharacterEncoding("UTF-8");
        String[] bks = badKey.split("\\|");
        if (isParameterMapOk(req, bks) && isHeaderOk(req, bks) && isBodyOk(req, bks)) {
            chain.doFilter(req, response);
        } else {
            PrintWriter writer = response.getWriter();
            writer.write(JSONObject.toJSONString(voRes));
            return;
        }
    }

    private boolean isParameterMapOk(WzHttpServletRequestWrapper r, String[] badKeys) {

        Map<String, String[]> p = r.getParameterMap();
        if (null == p || 0 == p.size()) {
            return true;
        } else {
            for (String k : p.keySet()) {
                String[] vs = p.get(k);
                if (null == vs || 0 == vs.length) {
                    continue;
                } else {
                    for (String v : vs) {
                        if (WzStrUtil.isNotBlank(v)) {
                            for (String bk : badKeys) {
                                if (bk.equalsIgnoreCase(v)) {
                                    return false;
                                }
                            }
                            v = escapeStr(v);
                        }
                    }
                }
            }
        }
        return true;
    }

    private boolean isHeaderOk(WzHttpServletRequestWrapper r, String[] badKeys) {
        Enumeration<String> hn = r.getHeaderNames();
        if (null == hn) {
            return true;
        } else {
            while (hn.hasMoreElements()) {
                String v = r.getHeader(hn.nextElement());
                if (WzStrUtil.isNotBlank(v)) {
                    for (String bk : badKeys) {
                        if (bk.equalsIgnoreCase(v)) {
                            return false;
                        }
                    }
                    v = escapeStr(v);
                }
            }
        }
        return true;
    }

    private boolean isBodyOk(WzHttpServletRequestWrapper r, String[] badKeys) {
        String bs = r.getBodyStr();
        if (WzStrUtil.isBlank(bs)) {
            return true;
        } else {
            JSONObject bsObj = JSONObject.parseObject(bs);
            for (String k : bsObj.keySet()) {
                if (bsObj.get(k) instanceof String) {
                    String v = bsObj.getString(k);
                    if (WzStrUtil.isNotBlank(v)) {
                        for (String bk : badKeys) {
                            if (bk.equalsIgnoreCase(v)) {
                                return false;
                            }
                        }
                        v = escapeStr(v);
                    }
                }
            }
        }
        return true;
    }

    private String escapeStr(String oriStr) {
        String s = oriStr;
        s = StringEscapeUtils.escapeEcmaScript(s);
        s = StringEscapeUtils.escapeHtml3(s);
        s = StringEscapeUtils.escapeHtml4(s);
        s = StringEscapeUtils.escapeXml(s);
        return s;
    }

    @Override
    public void destroy() {
        logger.debug("过滤器销毁");
    }

}
